//! Udp和Tcp的协议缓冲区。用于一个线程缓存写，一个线程缓存读。
//!
//!  0xff 0xFF  d d d d d d 校验byte 0xFE 0xFE
//!
//! 我们不使用Vec，而使用下面的形式，是为了让PackBuf能在多线程中Send。
//! 由于有Atomic类型的存在，不需要担心数据一致性的问题。
//! 如果PackBuf在多线程自由Send使用，请把PackBuf的指针发送， 看后面的例子。
//! 如果把PackBuf的指针发送到多个线程中，注意把PackBuf的保存好，如果PackBuf drop掉用的
//! 多个线程会引起内存错误。
//!
//! NOTE: 这个库只适合两个线程，一个读，一个写。 作为缓存使用。
pub mod error;

use error::Error;
use std::{
    mem::{forget, transmute},
    ptr::slice_from_raw_parts_mut,
    sync::atomic::{AtomicBool, AtomicUsize, Ordering},
};

use crate::error::{error_bad_pack, error_check_failed, error_read_to_end, ErrorKind};

const HEADER_CODE: [u8; 2] = [0xFF, 0xFF];
const TAIL_CODE: [u8; 2] = [0xFE, 0xFE];

type PackData = Vec<u8>;
#[derive(Debug)]
pub struct PackBuf {
    read_pos: AtomicUsize,  // 读的时候的位置
    write_pos: AtomicUsize, // 写的时候的位置
    loopback: AtomicBool,   // 当读写位置重合的时候，由这个标志指明是否存在数据

    len: usize, // 缓冲区的大小
    ptr: usize, // 指向缓冲区堆上的指针
    cap: usize, // 缓冲capacity大小。
}

impl PackBuf {
    pub fn new(len: usize) -> Self {
        let buf = vec![0u8; len];
        let ptr = buf.as_ptr() as usize;
        let len = buf.len();
        let cap = buf.capacity();
        forget(buf);
        Self {
            read_pos: AtomicUsize::new(0),
            write_pos: AtomicUsize::new(0),
            loopback: AtomicBool::new(false),
            len,
            ptr,
            cap,
        }
    }

    pub fn box_new(len: usize) -> Box<Self> {
        Box::new(Self::new(len))
    }

    /// 读出所有的正确包
    pub fn read_packs(&self) -> Vec<PackData> {
        let mut data = Vec::with_capacity(64);
        loop {
            let d = self.read_pack();
            match d {
                Ok(d) => data.push(d),
                Err(e) => {
                    if matches!(e.kind(), ErrorKind::CheckFaild(_) | ErrorKind::BadPack(_)) {
                        continue;
                    }
                    return data;
                }
            }
        }
    }

    /// 写一包数据
    /// 返回(写入成功的数据个数，原始数据的个数), 由于不知道数据包的大小，这个函数废弃, 组合使用generate_pack_data和write函数
    // pub fn write_pack(&self, data: &[u8]) -> (usize, usize) {
    //     let pack = Self::generate_pack_data(data);
    //     (self.write(&pack), pack.len())
    // }

    pub fn write(&self, data: &[u8]) -> usize {
        let read_pos = self.get_read_pos();
        let mut write_pos = self.get_write_pos();
        let buf = self.as_mut_slice();

        let empty_len = if write_pos == read_pos {
            if self.get_loopback() {
                return 0;
            } else {
                self.len
            }
        } else if write_pos > read_pos {
            self.len - (write_pos - read_pos)
        } else {
            read_pos - write_pos
        };
        let data_len = data.len();

        let mut ret_len = None;
        for i in 0..data_len {
            if empty_len == i {
                ret_len = Some(i);
                break;
            }
            buf[write_pos] = data[i];
            write_pos = self.pos_add(write_pos, 1);
            self.set_write_pos(write_pos);
        }

        if write_pos == read_pos {
            while let Err(_) =
                self.loopback
                    .compare_exchange(false, true, Ordering::Release, Ordering::Acquire)
            {
                // 表示之前的值还是true， read并没有来得及处理数据,确保true一定是在false的后面发生
                continue;
            }
        }
        if let Some(len) = ret_len {
            len
        } else {
            data_len
        }
    }

    pub fn generate_pack_data(data: &[u8]) -> Vec<u8> {
        let pack_len: usize = 2 + data.len() + 1 + 2;
        let mut write_data = Vec::with_capacity(pack_len);
        write_data.extend_from_slice(&HEADER_CODE);
        write_data.extend_from_slice(data);
        let mut check_code = write_data[0];
        for i in 1..write_data.len() {
            check_code ^= write_data[i];
        }
        write_data.extend_from_slice([check_code].as_slice());
        write_data.extend_from_slice(&TAIL_CODE);
        write_data
    }

    pub fn box_to_ptr(self: &Box<Self>) -> usize {
        let ptr: *const (*const (), *const ()) =
            unsafe { transmute::<&Box<Self>, *const (*const (), *const ())>(self) };
        unsafe { (*ptr).0 as usize }
    }

    pub fn ptr_to_ref<'a>(ptr: usize) -> &'a PackBuf {
        unsafe { &*transmute::<usize, *const PackBuf>(ptr) }
    }

    // ------------------------------------------------------------------------------------------------------------------------------
    // 读取一包数据
    fn read_pack(&self) -> Result<PackData, Error> {
        let mut read_pos = self.get_read_pos();
        read_pos = self.check_header_code(read_pos)?;
        let data = self.get_data_and_check_code(read_pos)?; // 成功之后，自动重置buf中的read_buf
        Self::calculate_check_code(&data)?;
        Ok(data[..data.len() - 1].to_vec())
    }

    // 检查是不是一包数据的开始, read_pos：当前的位置
    // 返回下一个位置
    fn check_header_code(&self, mut read_pos: usize) -> Result<usize, Error> {
        loop {
            let hd: Vec<u8> = self.peek(read_pos, 2, true)?; // peek具有检查是否在末尾的功能。
            if &hd == &HEADER_CODE {
                // 找到一个包的开始
                return Ok(self.pos_add(read_pos, 2));
            }
            read_pos = self.pos_add(read_pos, 1); // 向后滑动一个, 不用判断是否到达末尾，能到这里，代表peek了后面2个数据成功的
            self.set_read_pos(read_pos); // 重置buf中的reas_pos， 设置基点
            self.set_loopback(false); // 为了后面判断是否到达末尾
        }
    }

    // 获取数据 这个时候self.read_pos指向了包头的起始, 如果后面的数据不全或者错误的话，self.read_pos不用改变，等待数据接收一会
    fn get_data_and_check_code(&self, mut read_pos: usize) -> Result<Vec<u8>, Error> {
        let mut ret = Vec::with_capacity(256);
        loop {
            // 这里不需要检查loopback的原因就是因为我们找到了包头， self.read_pos已经定住，只需要对比pos就行
            let peer = self.peek(read_pos, 3, false).map_err(|e| {
                // 到位了尾部,还没有找到正确的包, 那么我们需要判断一下，self.read_pos是否等于self.write.如果相等，那么所有数据抛弃， 只需要设置loopback为false
                if self.get_read_pos() == self.get_write_pos() {
                    self.set_loopback(false); // 设置完毕之后， self.write_pos才能开始写
                } // 不相等的话，退出，让self.write_pos再写入一会
                e
            })?;
            ret.push(peer[0]); // 经过循环，这里最后压入的是checksum code
            let tail = &peer[peer.len() - 2..];
            if tail == &TAIL_CODE {
                self.set_read_pos(self.pos_add(read_pos, 3)); // 重置buf中的read_pos
                self.set_loopback(false);
                return Ok(ret);
            }

            if tail == &HEADER_CODE {
                self.set_read_pos(self.pos_add(read_pos, 3)); // 重置buf中的read_pos
                self.set_loopback(false);
                return Err(error_bad_pack("bad package, abandon it."));
            }
            read_pos = self.pos_add(read_pos, 1);
        }
    }

    // 计算校验码
    fn calculate_check_code(data: &[u8]) -> Result<(), Error> {
        let mut check_data = Vec::with_capacity(64);
        check_data.extend_from_slice(&HEADER_CODE);
        check_data.extend_from_slice(&data[0..data.len() - 1]);
        let mut tmp = check_data[0];
        for i in 1..check_data.len() {
            tmp ^= check_data[i];
        }
        if tmp == data[data.len() - 1] {
            Ok(())
        } else {
            Err(error_check_failed(&format!(
                "{}!={}",
                tmp,
                data[data.len() - 1]
            )))
        }
    }

    #[inline]
    fn pos_add(&self, mut num: usize, add: usize) -> usize {
        num += add;
        if num >= self.len {
            num - self.len
        } else {
            num
        }
    }

    // 如果read_pos和write_pos重合，这个时候需要判定loopback标志，如果为false， 那么到末尾了，如果true， 当前buf是满的
    // 有这么一种情况，buf的写线程非常的快，buf的读线程慢， 那么r_pos     w_pos ,转一圈回来，可能w_pos  r_pos, w_pos
    // 继续前进，这个时候w_pos和r_pos重合，looback为true， 那么这个r_pos就会一直读，没有停下来，一直在追赶w_pos.
    #[inline]
    fn check_to_end(&self, pos: usize, need_loopback: bool) -> Result<(), Error> {
        if need_loopback {
            if self.get_write_pos() == pos && !self.get_loopback() {
                return Err(error_read_to_end("check_to_end: read to end"));
            }
            Ok(())
        } else {
            if self.get_write_pos() == pos {
                return Err(error_read_to_end("check_to_end: read to end"));
            }
            Ok(())
        }
    }

    // 获取指定位置的数值
    // 调用这个函数之前，请手动确认缓冲区是否有数据，以及pos正确性。
    #[inline]
    fn get_data_from_pos(&self, pos: usize) -> u8 {
        let buf = self.as_mut_slice();
        buf[pos]
    }

    fn as_mut_slice(&self) -> &mut [u8] {
        let ptr = slice_from_raw_parts_mut(self.ptr as *mut u8, self.len);
        let ptr: &mut [u8] = unsafe { transmute(ptr) };
        ptr
    }

    #[inline]
    fn get_read_pos(&self) -> usize {
        self.read_pos.load(Ordering::Acquire)
    }

    #[inline]
    fn get_write_pos(&self) -> usize {
        self.write_pos.load(Ordering::Acquire)
    }

    // 改变self.read_pos同时把loopback标志修改为false，
    // 此函数一般在pos_add后面调用。
    #[inline]
    fn set_read_pos(&self, pos: usize) {
        self.read_pos.store(pos, Ordering::Release);
    }

    #[inline]
    fn set_write_pos(&self, pos: usize) {
        if self.get_write_pos() != pos {
            self.write_pos.store(pos, Ordering::Release)
        }
    }

    #[inline]
    fn set_loopback(&self, status: bool) {
        self.loopback.store(status, Ordering::Release);
    }

    #[inline]
    fn get_loopback(&self) -> bool {
        self.loopback.load(Ordering::Acquire)
    }

    // 从read_pos这个位置，获取num个数据，并不真正的改变self.read_pos
    // 失败的话，说明到了末尾。
    fn peek(&self, mut read_pos: usize, num: usize, need_loopback: bool) -> Result<Vec<u8>, Error> {
        self.check_to_end(read_pos, need_loopback)?;
        let mut bytes = Vec::with_capacity(num);
        for i in 0..num {
            if i != 0 {
                read_pos = self.pos_add(read_pos, 1);
                self.check_to_end(read_pos, need_loopback)?;
            }
            bytes.push(self.get_data_from_pos(read_pos));
        }
        Ok(bytes)
    }
}

impl Drop for PackBuf {
    fn drop(&mut self) {
        unsafe {
            Vec::from_raw_parts(self.ptr as *mut u8, self.len, self.cap);
        }
    }
}
#[cfg(test)]
mod tests {

    use std::time;

    use crate::PackBuf;

    #[test]
    fn test_pack_buf() {
        let pack_buf = PackBuf::new(24);
        println!("1: 初始化: pack_buf: {:?}", pack_buf);
        // 读写测试
        println!(">>>>>>>>>>>>>>>>>基本读写测试");
        let data = PackBuf::generate_pack_data([23, 45, 67, 89, 12, 55, 123].as_slice());
        pack_buf.write(&data); // write_ops: 12, read_ops: 0, loopback: false
        println!("2:{:?}", pack_buf);
        let datat = PackBuf::generate_pack_data([1, 2, 3, 4, 5, 6, 7].as_slice());
        pack_buf.write(&data); // write_ops: 0, read_ops: 0, loopback: true, 发生了重合， 但是通过loopback可以发现有数据.
        println!("3:{:?}", pack_buf);
        let data = pack_buf.read_packs(); // 虽然w_s = r_s， 但是其实是有数据的, 一次性有两个包的数据全部读出来.
        println!("4:{:?}", data); // [[1, 2, 3, 4, 5, 6, 7], [23, 45, 67, 89, 12, 55, 123]]
        println!("5:{:?}", pack_buf); // write_ops: 0, read_ops: 0, loopback: false, pos都变成0了，但是通过loopback=fasle，知道没有数据， 再次读取会返回空
        println!("6:{:?}", pack_buf.read_packs()); // 再次读取返回空
        println!("7:{:?}", pack_buf); // read_pos: 0, write_pos: 0, loopback: false

        // 测试不完全包
        println!(">>>>>>>>>>>>>>>>>测试不完全包");
        pack_buf.write([1, 2, 3, 4, 5, 6].as_slice()); // 由于不是正确的协议包， 读取包的时候，移动寻找正确的起始码
        println!("8:{:?}", pack_buf); // read_pos: 0, write_pos: 6, loopback: false,
        let data = pack_buf.read_packs();
        println!("9:{:?}", data); // 空的
        println!("10:{:?}", pack_buf); // 一直没有发现正确的起始码， read_pos: 5, write_pos: 6, loopback: false, 只是抛弃了5个，预留了一个，等待接收

        // 测试回环
        println!(">>>>>>>>>>>>>>>>>测试回环");
        let data = PackBuf::generate_pack_data([12u8; 18].as_slice());
        pack_buf.write(&data); // 写入23字节包数据, 正好写满了
        println!("11:一次性写满之后:{:?}", pack_buf); //read_pos: 5, write_pos: 5, loopback: true  write_pos写到了read_pos位置，loopback为true
        let data = pack_buf.read_packs();
        println!("12:data: {:?}", data); // data: [[12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12]] 23个字节，开始错误的那个被抛弃掉了
        println!("13: {:?}", pack_buf); // read_pos: 5, write_pos: 5, loopback: false 又回到了一起了

        // 测试坏包
        println!(">>>>>>>>>>>>>>>>>测试环包");
        pack_buf.write(
            [
                12, 12, 12, 12, 253, 254, 255, 255, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
                12, 12, 12, 12,
            ]
            .as_slice(),
        ); // 写入了24个字节，
        println!("14: {:?}", pack_buf); // read_pos: 5, write_pos: 5, loopback: true,
        let data = pack_buf.read_packs();
        println!("15:data: {:?}", data); // [] error:bad pack abandon it: bad package, abandon it. [12, 12, 12, 12, 253, 254]被判断为坏包，抛弃掉，
                                         //[255, 255, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,12, 12, 12, 12, 12,]被判断为不完全包，等待写入数据后再进行判断.
        println!("16:{:?}", pack_buf); // read_pos: 11, write_pos: 5, loopback: false, 和预期的一样， read_pos停留在了11的位置，也就是指向了255.

        // 测试无效包，就是一直找不到头码
        println!(">>>>>>>>>>>>>>>>>测试无效包");
        pack_buf.write([12, 12, 12, 12, 253, 253].as_slice()); // 再写入6个字节，这是buf已经满了，read_pos和write_pos重合， loopback 为true
        println!("17:{:?}", pack_buf); // read_pos: 11, write_pos: 11, loopback: true,
        let data = pack_buf.read_packs();
        println!("18:data: {:?}", data); // 空数据
        println!("19:{:?}", pack_buf); // read_pos: 11, write_pos: 11, loopback: false, 由于目前buf已经满了，但是没有发现正常的包，数据全部抛弃，直接清理缓冲区

        // 测试是否可以写了
        println!(">>>>>>>>>>>>>>>>>缓冲区清理后");
        let data = PackBuf::generate_pack_data([15u8; 15].as_slice());
        pack_buf.write(&data);
        println!("20: {:?}", pack_buf);
    }

    #[test]
    fn test_multi_thread() {
        let pack_buf = PackBuf::box_new(24);
        // 因为我们的pack_buf就是线程安全的，不需要再对packbuf进行Mutex操作了，直接把pack_buf的指针传递进两个线程中去。
        let ptr = pack_buf.box_to_ptr();
        let t1 = std::thread::spawn(move || {
            let pack_buf = PackBuf::ptr_to_ref(ptr);

            let data = PackBuf::generate_pack_data([12, 34, 56, 78, 12].as_slice());

            loop {
                let mut left = data.len();
                let mut data_ref = &data[..];

                loop {
                    let err = pack_buf.write(&data_ref[0..]);
                    println!(
                        "写入的数据个数: {}, 为:{:?}, left {}, data_ref: {:?}",
                        err,
                        &data_ref[0..err],
                        left,
                        data_ref
                    );
                    // 如果发生了错误，需要等待一下,让read 读一下
                    if err != left {
                        left -= err;
                        data_ref = &data_ref[err..];
                        std::thread::sleep(time::Duration::from_millis(10)); // 等待10ms
                        continue;
                    }
                    break;
                }
            }
        });

        let t2 = std::thread::spawn(move || {
            let pack_buf = PackBuf::ptr_to_ref(ptr);
            loop {
                let data = pack_buf.read_packs();
                if data.is_empty() {
                    std::thread::sleep(time::Duration::from_millis(10)); // 如果读到的数据为空，等待一会
                    continue;
                }
                println!("读到的数据为: {:?}", data);
            }
        });

        t1.join().unwrap();
        t2.join().unwrap();
    }
}
